#!/usr/bin/python
# -*- coding: utf-8 -*-
# File: model.py
# Author: Tomás Vírseda
# License: GPL v3
# Description:  test the metadata rdf store
# TODO: Use testing modules

import os
import datetime
import sys
if sys.version_info < (2, 4, 0):
    from sets import Set as set
    del sys
from StringIO import StringIO
#import distutils.version
#import gc

from rdflib.Graph import Graph
from rdflib import URIRef
from rdflib.Graph import ConjunctiveGraph
from rdflib.sparql.sparqlGraph  import SPARQLGraph
from rdflib.sparql.graphPattern import GraphPattern
from rdflib import Literal
from rdflib.TextIndex import TextIndex
from rdflib.sparql import Query
from rdflib.sparql.parser import doSPARQL


from vazaarlib.namespaces import NIE, NAO, NFO, RDF, NSBINDINGS
from vazaarlib.utils import get_logger


log = get_logger("Model")

def serialize_rdfxml(graph):
    try:
        graph.bind('rdf', RDF)
        graph.bind('nfo', NFO)
        graph.bind('nao', NAO)
        graph.bind('nie', NIE)
        graph.bind('nfo', NFO)
        #print graph.serialize(format="pretty-xml")
        output = graph.serialize(format="pretty-xml")
        return output
    except Exception, e:
        print "Serialize error: %s" % e

"""
foreach namespace
    foreach predicate
        get object, frequency
"""
def make_report(store):
    t1 = datetime.datetime.now()
    report = {}

    for namespace in get_namespaces(store):
        report[str(namespace)] = {}

    for predicate in get_predicates(store, 'make_report'):
        ns = get_namespace_from_predicate(store, predicate)
        qname = get_qname_from_predicate(store,predicate)
        frequency = get_qname_frequency(store, predicate)
        report[str(ns)][str(qname)] = frequency

    t2 = datetime.datetime.now()
    log.debug("\t\tmaking report: %s" % (t2 - t1))

    return report

def get_qname_from_predicate(store, predicate):
    namespace, uriref, qname = store.compute_qname(predicate)

    return qname

def get_namespace_from_predicate(store, predicate):
    namespace, uriref, qname = store.compute_qname(predicate)

    return namespace

def get_namespaces(store):
    namespaces = []
    predicates = get_predicates(store, 'get_namespaces')

    for predicate in predicates:
        namespace, uriref, qname = store.compute_qname(predicate)
        namespaces.append(namespace)

    return namespaces

def get_predicates(store, function):
    t1 = datetime.datetime.now()
    select = ("?predicate")
    where = GraphPattern([("?subject", "?predicate", "?extension")])
    sparqlGrph = SPARQLGraph(store)
    t2 = datetime.datetime.now()
    log.debug("\tgetting predicates for %s: %s secs" % (function, (t2 -t1)))
    return Query.query(sparqlGrph, select, where, initialBindings=NSBINDINGS)

def get_predicate_qnames(store):
    qnames = []
    predicates = get_predicates(store, 'get_predicate_qnames')

    for predicate in predicates:
        namespace, uriref, qname = store.compute_qname(predicate)
        qnames.append(qname)

    return qnames

def get_qname_frequency(store, predicate):
    relations = list(store.subject_objects(predicate))
    freq = {}
    for s, o in relations:
        try:
            count = freq[str(o)]
            freq[str(o)] = count + 1
        except Exception, e:
            freq[str(o)] = 1

    return freq


def get_extensions_frequency(store, qname):
    relations = list(store.subject_objects(NFO[qname]))
    extensions = set()
    freq = {}
    for s, o in relations:
        try:
            count = freq[o]
            freq[o] = count + 1
        except Exception, e:
            extensions.add(o)
            freq[o] = 1
    #del extensions
    return freq


def get_resources_by_extension(store, ext=""):
    select = ("?id", "?type", "?title")
    where = GraphPattern([
        ("?id", RDF.type, "?type"),
        ("?id", NIE['title'], "?title"),
        ("?id", NFO['mimetype'], "?type"),
        ("?id", NFO['extension'], Literal(ext)),
        ("?id", NFO['scheme'], Literal('file'))
    ])
    sparqlGrph = SPARQLGraph(store)
    resources = Query.query(sparqlGrph, select, where, initialBindings=None)

    return resources

def get_resources_from_collection(cid, store):
    #print store.serialize(format="n3")
    select = ("?rid")
    where = GraphPattern([
        (URIRef(cid), RDF.type, PIMO['Collection']),
        (URIRef(cid), NIE['hasLogicalPart'], "?rid"),
    ])

    sparqlGrph = SPARQLGraph(store)
    resources = Query.query(sparqlGrph, select, where, initialBindings=None)

    #print "resources in collection: %d" % len(resources)
    return resources


def get_collections(store):
    select = ("?cid")
    where = GraphPattern([
        ("?cid", RDF.type, PIMO['Collection'])
    ])
    sparqlGrph = SPARQLGraph(store)
    colids = Query.query(sparqlGrph, select, where, initialBindings=None)
    #print "collections: %d" % len(colids)
    return colids # The resource can belong to None, 1 or more collections


def is_resource_in_collection(resid, store):
    select = ("?colid")
    where = GraphPattern([
        ("?colid", NIE['hasLogicPart'], resid)
    ])

    sparqlGrph = SPARQLGraph(store)
    colids = Query.query(sparqlGrph, select, where, initialBindings=None)

    return colids # The resource can belong to None, 1 or more collections


def get_info_from_resource_collection(col, store):
    select = ("?title")
    where = GraphPattern([
        (col, RDF.type, "?type"),
        (col, NIE['title'], "?title")
    ])
    # TODO: add FILTER for avoiding Folder type. How?
    sparqlGrph = SPARQLGraph(store)
    info = Query.query(sparqlGrph, select, where, initialBindings=None)

    if not info:
        return "Back"

    return str(info[0])

def get_collection_from_resource(store, id):
    #id = URIRef(identifier)
    #print id
    #print store.serialize(format="pretty-xml")
    select = ("?s", "?p", "?o")
    where = GraphPattern([
        ("?s", "?p", "?o")
    ])
    sparqlGrph = SPARQLGraph(store)
    info = Query.query(sparqlGrph, select, where, initialBindings=None)

    return info

def get_info2_from_resource(res, store):
    select = ("?predicate", "?object")
    where = GraphPattern([
        (res, "?predicate", "?object"),
    ])

    sparqlGrph = SPARQLGraph(store)
    info = Query.query(sparqlGrph, select, where, initialBindings=None)

    return info

def get_info_from_resource(store, id):
    t1 = datetime.datetime.now()
    resource = {}
    resource[id] = {}

    select = ("?pred", "?obj")
    where = GraphPattern([
                            (URIRef(id), "?pred", "?obj")
                        ])
    sparqlGrph = SPARQLGraph(store)
    res = Query.query(sparqlGrph, select, where, initialBindings=None)
    for pred, obj in res:
        resource[id][get_qname_from_predicate(store, pred)] = obj

    return resource

    """
    select = ("?title", "?name", "?type", "?url", "?mime", "?subtype", "?ext")
    where = GraphPattern([
        (res, RDF.type, "?type"),
        (res, NIE['title'], "?title")
    ])
    opt = GraphPattern([
        (res, NIE['mimeType'], "?mime"),
        (res, NIE["mimeSubtype"], "?subtype"),
        (res, NFO['fileExtension'], "?ext"),
        (res, NFO['fileUrl'], "?url")
    ])
    # TODO: add FILTER for avoiding Folder type. How?
    sparqlGrph = SPARQLGraph(store)
    info = Query.query(sparqlGrph, select, where, opt, initialBindings=None)

    title = str(info[0][0])
    basename = str(info[0][1])
    # the last chunk is the class of the resource
    type = str((info[0][2].rpartition('/')[-1:])[0])
    url = str(info[0][3])
    mime = str(info[0][4])
    subtype = str(info[0][5])
    ext = str(info[0][6])
    #print "title: %s, basename: %s, type: %s, url: %s, mime: %s, ext: %s" % (title, basename, type, url, mime, ext)
    #print "Url:", url, "\tType:", type, "\tMime:", mime

    return title, basename, type, url, mime, subtype, ext
    """

def get_resources(store):
    select = ("?id")
    where = GraphPattern([
        ("?id", RDF.type, "?type")
    ])

    sparqlGrph = SPARQLGraph(store)
    resources = Query.query(sparqlGrph, select, where, initialBindings=None)

    return resources


def get_url_from_resource(store, id):
    select = ("?url")
    where = GraphPattern([
        (URIRef(id), NFO['fileUrl'], "?url")
    ])
    sparqlGrph = SPARQLGraph(store)
    res = Query.query(sparqlGrph, select, where, initialBindings=None)
    try:
        return str(res[0])
    except:
        return None


def get_mime_from_resource(store, id):
    select = ("?mime")
    where = GraphPattern([
        (URIRef(id), NIE['mimeType'], "?mime"),
    ])
    sparqlGrph = SPARQLGraph(store)
    res = Query.query(sparqlGrph, select, where, initialBindings=None)
    try:
        return str(res[0])
    except:
        return None

def get_name_from_resource(store, id):
    select = ("?name")
    where = GraphPattern([
        (URIRef(id), NIE['title'], "?name"),
    ])
    sparqlGrph = SPARQLGraph(store)
    res = Query.query(sparqlGrph, select, where, initialBindings=None)
    try:
        return str(res[0])
    except:
        return None

def get_type_from_resource(store, id):
    select = ("?type")
    where = GraphPattern([
        (URIRef(id), RDF.type, "?type"),
    ])
    sparqlGrph = SPARQLGraph(store)
    res = Query.query(sparqlGrph, select, where, initialBindings=None)
    try:
        return res[0]
    except:
        return None

def serialize_resource(store, id=None):
    node = ConjunctiveGraph()

    if not id:
        return None

    s = URIRef(id)

    select = ("?p", "?o")
    where = GraphPattern([
        (s, "?p", "?o")
    ])
    sparqlGrph = SPARQLGraph(store)
    metadata = Query.query(sparqlGrph, select, where, initialBindings=NSBINDINGS)

    for p, o in metadata:
        node.add((s, p, o))

    output = serialize_rdfxml(node)
    if not output:
        return "Not ouput from node"
    return output

def build_store_from_identifiers(store, identifiers):
    g = ConjunctiveGraph()
    t1 = datetime.datetime.now()
    for id in identifiers:
        tb1 = datetime.datetime.now()
        select = ("?pred", "?obj")
        where = GraphPattern([
            (URIRef(id), "?pred", "?obj")
        ])
        sparqlGrph = SPARQLGraph(store)
        res = Query.query(sparqlGrph, select, where, initialBindings=None)
        for pred, obj in res:
            g.add((id, pred, obj))
        tb2 = datetime.datetime.now()
        #log.debug("\t\tnode %s built in %s secs" % (id, (tb2 - tb1)))
    t2 = datetime.datetime.now()
    log.debug("\tbuilding temporal graph in %s secs" % (t2 - t1))

    return g


def get_resources_by_property(store, property, value):

    select = ("?id")
    where = GraphPattern([
        ("?id", NFO[property], Literal(value))
    ])

    sparqlGrph = SPARQLGraph(store)
    resources = Query.query(sparqlGrph, select, where, initialBindings=None)

    return resources

def simple_sparql_search(store, text, case=False, word=False):
    """
    Search a string in all literals of a given graph. It only searches
    in predicates that contains strings.
    """
    t1 = datetime.datetime.now()

    if case == False:
        term = text.upper()
    else:
        term = text

    allowed = (
                NIE['title'],
                NFO['fileUrl'],
                NFO['filePort'],
                NFO['fileStatus']
            )

    def build_query(predicate, term):
        query = """
        SELECT ?id
        WHERE { ?id %s ?object .
        FILTER regex(?object, %s, "i") }
        """ % (predicate, term)
        print query

        return query

    collection = set()
    for predicate in allowed:
        query = build_query(predicate, term)
        sparqlGrph = SPARQLGraph(store)
        result = doSPARQL(StringIO(query), sparqlGrph)

        #store.parse(query)
        #print StringIO(query)
        #store.parse(StringIO(query))
        #results = store.query(query, initialBindings=None)
        #print len(results), results
        #sparqlGrph = SPARQLGraph(store)
        #resources = Query.query(sparqlGrph, select, where, opt, initialBindings=None)
        """
        for res in resouces:
            collection.add(res)

        print "sparql", len(collection)
        return collection
        """
        """
        PREFIX nao: <http://www.semanticdesktop.org/ontologies/nao/>
        PREFIX nie: <http://www.semanticdesktop.org/ontologies/nie/>
        PREFIX nfo: <http://www.semanticdesktop.org/ontologies/nfo/>
        PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
        """

def get_subjects_objects(store):
    select = ("?subject", "?object")
    where = GraphPattern([
        ("?subject", NIE['title'], "?object"),
    ])
    sparqlGrph = SPARQLGraph(store)
    res = Query.query(sparqlGrph, select, where, initialBindings=None)


    return res
